package aceim.protocol.snuk182.icq.inner.dataprocessing; import java.io.UnsupportedEncodingException; import java.util.Date; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import aceim.protocol.snuk182.icq.inner.ICQConstants; import aceim.protocol.snuk182.icq.inner.ICQException; import aceim.protocol.snuk182.icq.inner.ICQServiceInternal; import aceim.protocol.snuk182.icq.inner.ICQServiceResponse; import aceim.protocol.snuk182.icq.inner.dataentity.Flap; import aceim.protocol.snuk182.icq.inner.dataentity.ICBMParams; import aceim.protocol.snuk182.icq.inner.dataentity.RateGroup; import aceim.protocol.snuk182.icq.inner.dataentity.RateLimit; import aceim.protocol.snuk182.icq.inner.dataentity.Snac; import aceim.protocol.snuk182.icq.inner.dataentity.TLV; import aceim.protocol.snuk182.icq.utils.MD5; import aceim.protocol.snuk182.icq.utils.ProtocolUtils; public class AuthenticationProcessor extends AbstractFlapProcessor { private final byte[] pwRoastArray = { (byte) 0xF3, 0x26, (byte) 0x81, (byte) 0xC4, 0x39, (byte) 0x86, (byte) 0xDB, (byte) 0x92, 0x71, (byte) 0xA3, (byte) 0xB9, (byte) 0xE6, 0x53, 0x7A, (byte) 0x95, 0x7C }; private byte[] authCookie = null; private String reconnectAddress = null; private int reconnectPort = 0; public boolean isSecureLogin = false; private static final String AIM_MD5_STRING = "AOL Instant Messenger (SM)"; private boolean endLogin = false; private ScheduledFuture<?> task; private ScheduledThreadPoolExecutor startupTimer = new ScheduledThreadPoolExecutor(1); private AuthExpireTimerTask expireTimerTask = new AuthExpireTimerTask(); @Override public void init(ICQServiceInternal service) throws ICQException { super.init(service); service.log("---------------auth thread---------------"); } private Flap sendCookie() throws ICQException { service.log("--- send cookie"); Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_START; TLV[] tlvs = new TLV[2]; tlvs[0] = new TLV((short) 0x0, new byte[] { 0x00, 0x01 }); tlvs[1] = new TLV(ICQConstants.TLV_AUTHCOOKIE, authCookie); flap.tlvData = tlvs; return flap; // service.getRunnableService().sendToSocket(flap); } private Flap createPlainAuthRequest(boolean sendAuthData) throws ICQException { service.log("--- plain auth request"); Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_START; TLV[] tlvs; if (sendAuthData) { tlvs = new TLV[5]; tlvs[0] = new TLV((short) 0x0, new byte[] { 0x00, 0x01 }); TLV screenNameTlv = new TLV(); screenNameTlv.type = ICQConstants.TLV_SCREENNAME; screenNameTlv.value = service.getUn().getBytes(); tlvs[1] = screenNameTlv; tlvs[2] = new TLV(ICQConstants.TLV_NEWPASSWORD, roastPw(service.getPw())); tlvs[3] = new TLV(ICQConstants.TLV_CLIENTIDENTITY, new String("Asia 0.5.2a").getBytes()); byte[] clientid = { (byte) 0x88, (byte) 0x88 }; tlvs[4] = new TLV(ICQConstants.TLV_CLIENTID, clientid); } else { tlvs = new TLV[1]; tlvs[0] = new TLV((short) 0x0, new byte[] { 0x00, 0x01 }); } flap.tlvData = tlvs; return flap; } private Flap createMD5Request() throws ICQException { service.log("--- md5 auth request"); Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_AUTHENTICATE; data.subtypeId = ICQConstants.SNAC_AUTHENTICATE_MD5AUTHKEYREQ; data.hFlag = (byte) 0x0; data.lFlag = (byte) 0x0; data.requestId = 0; byte[] name; try { name = service.getUn().getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { name = service.getUn().getBytes(); } TLV screenname = new TLV(); screenname.type = 0x01; screenname.value = name; TLV tlv1 = new TLV(); tlv1.type = (short) 0x004b; TLV[] tlvs = new TLV[] { screenname, tlv1 }; data.data = tlvs; flap.data = data; return flap; } private byte[] roastPw(String pws) throws ICQException { byte[] pw = pws.getBytes(); byte[] pwhash = new byte[pw.length]; int ln; // they don't support passwords longer than 8 symbols (facepalm) if (pw.length > 8) { ln = 8; } else { ln = pw.length; } for (int i = 0; i < ln; i++) { if (i + 1 <= pwRoastArray.length) { pwhash[i] = (byte) (pw[i] ^ pwRoastArray[i]); } else { pwhash[i] = pw[i]; } } return pwhash; } @Override protected void internalFlapMap(Flap flap) throws ICQException { if (flap == null) return; switch (flap.channel) { case ICQConstants.FLAP_CHANNELL_START: if (authCookie != null) { service.getServiceResponse().respond(ICQServiceResponse.RES_CONNECTING, 4); service.getRunnableService().sendToSocket(sendCookie()); } else { task = startupTimer.schedule(expireTimerTask, 60, TimeUnit.SECONDS); service.getServiceResponse().respond(ICQServiceResponse.RES_CONNECTING, 2); service.getRunnableService().sendToSocket(createPlainAuthRequest(!isSecureLogin)); if (isSecureLogin) { service.getRunnableService().sendToSocket(createMD5Request()); } } break; case ICQConstants.FLAP_CHANNELL_DATA: internalSnacMap(flap.data); break; case ICQConstants.FLAP_CHANNELL_CLOSE: /* * if (isSecureLogin){ return; } */ if (flap.tlvData != null) { for (int i = 0; i < flap.tlvData.length; i++) { TLV tlv = flap.tlvData[i]; internalTLVMap(tlv); } } tryConnectingBOS(); break; } } private void tryConnectingBOS() { if (reconnectAddress != null) { service.log("reconnect to " + reconnectAddress); service.setCurrentState(ICQServiceInternal.STATE_CONNECTING_BOS); } else { deactivateTimer(); } service.getRunnableService().disconnect(); if (reconnectAddress != null) { service.getServiceResponse().respond(ICQServiceResponse.RES_CONNECTING, 3); service.setCurrentState(ICQServiceInternal.STATE_AUTHENTICATING); service.runService(reconnectAddress, reconnectPort); permitList.clear(); denyList.clear(); ignoreList.clear(); } else { deactivateTimer(); } } @Override protected void internalTLVMap(TLV tlv) { if (tlv == null) { return; } switch (tlv.type) { case ICQConstants.TLV_EVIL: break; case ICQConstants.TLV_SCREENNAME: if (service.getOnlineInfo() != null) { service.getOnlineInfo().userClass = ProtocolUtils.bytes2ShortBE(tlv.value); service.log(" user class: " + service.getOnlineInfo().userClass); } break; case ICQConstants.TLV_ERRORDESCRIPTIONURL: String errorUrl = ProtocolUtils.getEncodedString(tlv.value); service.log(errorUrl); if (errorUrl.indexOf(ICQConstants.ERROR_BADCREDENTIALS) > -1) { service.lastConnectionError = ICQServiceInternal.ERROR_WRONG_PASSWORD; } break; case ICQConstants.TLV_RECONNECTADDRESS: if (reconnectAddress != null) { service.getOnlineInfo().memberSinceTime = ProtocolUtils.bytes2Date(tlv.value); service.log(" member since: " + service.getOnlineInfo().memberSinceTime); } else { reconnectAddress = new String(tlv.value).split(":")[0]; reconnectPort = Integer.parseInt(new String(tlv.value).split(":")[1]); service.log(" reconnect: " + reconnectAddress + ":" + reconnectPort); } break; case ICQConstants.TLV_AUTHCOOKIE: authCookie = tlv.value; break; case ICQConstants.TLV_CLIENTIDENTITY: if (service.getOnlineInfo() != null) { service.getOnlineInfo().signonTime = ProtocolUtils.bytes2Date(tlv.value); service.log(" signon time: " + service.getOnlineInfo().signonTime); } break; case ICQConstants.TLV_PERSONALTEXT: /* * if (service.getOnlineInfo()!=null){ * service.getOnlineInfo().setPersonalText * (ProtocolUtils.bytes2ShortBE(tlv.value)); * service.log(" personal text: " * +service.getOnlineInfo().getPersonalText()); } */ break; case ICQConstants.TLV_DCINFO: if (service.getOnlineInfo() != null) { try { service.getOnlineInfo().dcInfo = service.getOnlineInfoEngine().parseDCInfo(tlv.value); service.log("--- online info"); } catch (ICQException e) { // to do } } break; case ICQConstants.TLV_RECONNECTHOST: if (service.getOnlineInfo() != null) { try { service.getOnlineInfo().extIP = ProtocolUtils.unsignedByte2Short(tlv.value[0]) + "." + ProtocolUtils.unsignedByte2Short(tlv.value[1]) + "." + ProtocolUtils.unsignedByte2Short(tlv.value[2]) + "." + ProtocolUtils.unsignedByte2Short(tlv.value[3]); } catch (Exception e) { service.getOnlineInfo().extIP = ""; } service.log(" external ip: " + service.getOnlineInfo().extIP); } break; case ICQConstants.TLV_CLIENTIDLE: if (service.getOnlineInfo() != null) { service.getOnlineInfo().onlineTime = ProtocolUtils.bytes2IntBE(tlv.value); service.log(" online since: " + service.getOnlineInfo().onlineTime); } break; case ICQConstants.TLV_DISTRIBUTIONNUMBER: if (service.getOnlineInfo() != null) { service.getOnlineInfo().distribNumber = tlv.value[0]; service.log(" distribution: " + service.getOnlineInfo().distribNumber); } break; case ICQConstants.TLV_ERRORSUBCODE: if (tlv.value != null && tlv.value.length > 1 && tlv.value[1] == 0x18) { service.lastConnectionError = ICQServiceInternal.ERROR_RATE_LIMIT_EXCEEDED; } break; default: if (service.getOnlineInfo() != null) { service.getOnlineInfo().tlvs.add(tlv); service.log(" unknown tlv: " + ProtocolUtils.getSpacedHexString(ProtocolUtils.int2ByteBE(tlv.type))); } break; } } @Override protected void internalSnacMap(Snac snac) throws ICQException { if (snac == null) return; switch (snac.getServiceId()) { case ICQConstants.SNAC_FAMILY_GENERIC: switch (snac.subtypeId) { case ICQConstants.SNAC_GENERIC_SERVERSUPPORTEDFAMILIES: service.setServerSupportedFamilies(ProtocolUtils.byteArrayToShortArrayBE(snac.plainData)); service.getServiceResponse().respond(ICQServiceResponse.RES_CONNECTING, 5); service.getRunnableService().sendToSocket(sendClientFamiliesVersions()); break; case ICQConstants.SNAC_GENERIC_RATELIMITINFORES: parseRateLimits(snac); Flap clRequest; if (service.getBuddyList().itemNumber > 0 && service.getBuddyList().lastUpdateTime != null) { clRequest = requestContactListUpdate(service.getBuddyList().lastUpdateTime, service.getBuddyList().itemNumber); } else { clRequest = requestContactList(); } Flap[] flaps = new Flap[] { clRequest, sendRateLimitsAck(), requestOnlineInfo(), requestSSIServiceLimits(), requestLocationServiceLimits(), requestBuddylistServiceLimits(), requestMessagingServiceLimits(), requestPrivacyServiceLimits() }; service.getServiceResponse().respond(ICQServiceResponse.RES_CONNECTING, 7); service.getRunnableService().sendMultipleToSocket(flaps); break; case ICQConstants.SNAC_GENERIC_OWNINFORES: service.getOnlineInfoEngine().parseOnlineInfo(snac, service.getOnlineInfo()); service.getServiceResponse().respond(ICQServiceResponse.RES_ACCOUNTUPDATED, service.getOnlineInfo()); if (service.getCurrentState() == ICQServiceInternal.STATE_AUTHENTICATING && endLogin) { service.getServiceResponse().respond(ICQServiceResponse.RES_KEEPALIVE); service.startMainProcessor(); deactivateTimer(); } break; case ICQConstants.SNAC_GENERIC_SERVERSERVICESVERSIONRES: service.getServiceResponse().respond(ICQServiceResponse.RES_CONNECTING, 6); service.getRunnableService().sendToSocket(requestRateLimits()); break; } break; case ICQConstants.SNAC_FAMILY_LOCATION: switch (snac.subtypeId) { case ICQConstants.SNAC_LOCATION_PARAMRES: try { snac.data = service.getDataParser().parseTLV(snac.plainData); } catch (ICQException e) { service.log(e); } break; } break; case ICQConstants.SNAC_FAMILY_BUDDYLISTMGMT: switch (snac.subtypeId) { case ICQConstants.SNAC_BUDDYLISTMGMT_PARAMRES: try { snac.data = service.getDataParser().parseTLV(snac.plainData); } catch (ICQException e) { service.log(e); } break; } break; case ICQConstants.SNAC_FAMILY_MESSAGING: switch (snac.subtypeId) { case ICQConstants.SNAC_MESSAGING_PARAMRES: service.setMessageParams(parseICBMParams(snac.plainData)); break; } break; case ICQConstants.SNAC_FAMILY_PRIVACYMGMT: switch (snac.subtypeId) { case ICQConstants.SNAC_PRIVACYMGMT_PARAMRES: parsePrivacyParams(snac.plainData); break; } break; case ICQConstants.SNAC_FAMILY_SERVERSIDEINFO: switch (snac.subtypeId) { case ICQConstants.SNAC_SERVERSIDEINFO_PARAMRES: parseSSIParams(snac); break; case ICQConstants.SNAC_SERVERSIDEINFO_CLRES: parseBuddyList(snac.plainData, snac.lFlag == 1); case ICQConstants.SNAC_SERVERSIDEINFO_LOCALSSIUPTODATE: Flap[] flaps = new Flap[] { sendCapabilities(), sendICBMParameters(), sendSSIActivate() }; service.getServiceResponse().respond(ICQServiceResponse.RES_CONNECTING, 9); service.getRunnableService().sendMultipleToSocket(flaps); endLogin = true; break; } break; case ICQConstants.SNAC_FAMILY_AUTHENTICATE: switch (snac.subtypeId) { case ICQConstants.SNAC_AUTHENTICATE_MD5AUTHKEYRES: parseMD5Key(snac.plainData); break; case ICQConstants.SNAC_AUTHENTICATE_LOGINRES: snac.data = service.getDataParser().parseTLV(snac.plainData); parseMD5LoginResult(snac); break; } break; } } private void parseMD5LoginResult(Snac snac) { if (snac == null || snac.data == null) { service.lastConnectionError = ICQServiceInternal.ERROR_WRONG_PASSWORD; service.getRunnableService().disconnect(); return; } for (TLV tlv : snac.data) { internalTLVMap(tlv); } // tryConnectingBOS(); } private void parseMD5Key(byte[] data) { int keyLength = ProtocolUtils.unsignedShort2Int(ProtocolUtils.bytes2ShortBE(data, 0)); byte[] key = new byte[keyLength]; System.arraycopy(data, 2, key, 0, (int) keyLength); proceedMD5Login(key); } private void proceedMD5Login(byte[] key) { Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_AUTHENTICATE; data.subtypeId = ICQConstants.SNAC_AUTHENTICATE_LOGINREQ; data.requestId = ICQConstants.SNAC_AUTHENTICATE_LOGINREQ; TLV uinTlv = new TLV(); uinTlv.type = 0x1; try { uinTlv.value = service.getUn().getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { uinTlv.value = service.getUn().getBytes(); } TLV pwTlv = new TLV(); pwTlv.type = 0x25; byte[] pwHash = new MD5().calculate(service.getPw().getBytes()); byte[] aimHash = AIM_MD5_STRING.getBytes(); byte[] md5buf = new byte[key.length + pwHash.length + aimHash.length]; int pos = 0; System.arraycopy(key, 0, md5buf, pos, key.length); pos += key.length; System.arraycopy(pwHash, 0, md5buf, pos, pwHash.length); pos += pwHash.length; System.arraycopy(aimHash, 0, md5buf, pos, aimHash.length); pwTlv.value = new MD5().calculate(md5buf); TLV unk = new TLV((short) 0x4c, new byte[0]); data.data = new TLV[] { uinTlv, pwTlv, unk }; flap.data = data; service.getRunnableService().sendToSocket(flap); } private Flap sendSSIActivate() throws ICQException { Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_SERVERSIDEINFO; data.subtypeId = ICQConstants.SNAC_SERVERSIDEINFO_SERVERCLLOAD; data.requestId = ICQConstants.SNAC_SERVERSIDEINFO_SERVERCLLOAD; flap.data = data; return flap; } private Flap sendICBMParameters() throws ICQException { Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_MESSAGING; data.subtypeId = ICQConstants.SNAC_MESSAGING_PARAMSET; data.requestId = ICQConstants.SNAC_MESSAGING_PARAMSET; byte[] plainData = new byte[] { 0, 0, 0, 0, 0, 0xb, 0x1f, 0x40, 3, (byte) 0xe7, 3, (byte) 0xe7, 0, 0, 0, 0 };// TODO // fix! data.plainData = plainData; flap.data = data; return flap; } private Flap sendCapabilities() throws ICQException { Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_LOCATION; data.subtypeId = ICQConstants.SNAC_LOCATION_USERINFOSET; data.requestId = ICQConstants.SNAC_LOCATION_USERINFOSET; TLV clsids = new TLV(); clsids.type = 0x5; byte[] rawData = new byte[16 * 10 + ((service.getOnlineInfo().qipStatus != null) ? 16 : 0)]; int pos = 0; System.arraycopy(ICQConstants.CLSID_UTF, 0, rawData, pos, 16); pos += 16; System.arraycopy(ICQConstants.CLSID_DIRECT, 0, rawData, pos, 16); pos += 16; System.arraycopy(ICQConstants.CLSID_ICQUTF, 0, rawData, pos, 16); pos += 16; System.arraycopy(ICQConstants.CLSID_SRV_RELAY, 0, rawData, pos, 16); pos += 16; System.arraycopy(ICQConstants.CLSID_CLIENTINFOPREFIX, 0, rawData, pos, 16); pos += 16; System.arraycopy(ICQConstants.CLSID_TYPING, 0, rawData, pos, 16); pos += 16; System.arraycopy(ICQConstants.CLSID_AIM_FILERECEIVE, 0, rawData, pos, 16); pos += 16; System.arraycopy(ICQConstants.CLSID_AIM_FILESEND, 0, rawData, pos, 16); pos += 16; System.arraycopy(ICQConstants.CLSID_ASIA, 0, rawData, pos, 16); pos += 16; /* * System.arraycopy(new String("Asia 0.5.0.4.001").getBytes(), 0, * rawData, pos, 16); pos+=16; */ System.arraycopy(ICQConstants.CLSID_XTRAZ, 0, rawData, pos, 16); pos += 16; if (service.getOnlineInfo().qipStatus != null) { System.arraycopy(service.getOnlineInfo().qipStatus, 0, rawData, pos, 16); pos += 16; } clsids.value = rawData; data.data = new TLV[] { clsids }; flap.data = data; return flap; } private void parseSSIParams(Snac snac) throws ICQException { try { service.setSSILimits(service.getDataParser().parseTLV(snac.plainData)); } catch (ICQException e) { service.log(e); } } private void parsePrivacyParams(byte[] in) throws ICQException { try { TLV[] tlvs = service.getDataParser().parseTLV(in); for (int i = 0; i < tlvs.length; i++) { if (tlvs[i].type == 0x01) { service.setMaxVisibleListLength(ProtocolUtils.unsignedShort2Int(ProtocolUtils.bytes2ShortBE(tlvs[i].value))); service.log(" max visible items:" + service.getMaxVisibleListLength()); } if (tlvs[i].type == 0x02) { service.setMaxInvisibleListLength(ProtocolUtils.unsignedShort2Int(ProtocolUtils.bytes2ShortBE(tlvs[i].value))); service.log(" max invisible items:" + service.getMaxInvisibleListLength()); } } } catch (ICQException e) { service.log(e); } } private ICBMParams parseICBMParams(byte[] plainData) throws ICQException { if (plainData == null || plainData.length < 16) return null; ICBMParams params = new ICBMParams(); params.channel = ProtocolUtils.bytes2ShortBE(plainData, 0); params.flags = ProtocolUtils.bytes2IntBE(plainData, 2); params.maxMessageSnacLength = ProtocolUtils.unsignedShort2Int(ProtocolUtils.bytes2ShortLE(plainData, 6)); params.maxSenderWarningLevel = ProtocolUtils.unsignedShort2Int(ProtocolUtils.bytes2ShortBE(plainData, 8)); params.maxReceiverWarningLevel = ProtocolUtils.unsignedShort2Int(ProtocolUtils.bytes2ShortBE(plainData, 10)); params.minimumMessageInterval = ProtocolUtils.unsignedShort2Int(ProtocolUtils.bytes2ShortBE(plainData, 12)); params.smth = ProtocolUtils.bytes2ShortBE(plainData, 14); service.log(params + ""); return params; } private Flap requestOnlineInfo() throws ICQException { service.log("--- request online info"); Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_GENERIC; data.subtypeId = ICQConstants.SNAC_GENERIC_OWNINFOREQ; data.requestId = ICQConstants.SNAC_GENERIC_OWNINFOREQ; flap.data = data; return flap; // service.getRunnableService().sendToSocket(flap); } private Flap requestSSIServiceLimits() throws ICQException { service.log("--- request SSI limits"); Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_SERVERSIDEINFO; data.subtypeId = ICQConstants.SNAC_SERVERSIDEINFO_PARAMREQ; data.requestId = ICQConstants.SNAC_SERVERSIDEINFO_PARAMREQ; TLV tlv = new TLV(); tlv.type = (short) 0x0b; tlv.value = new byte[] { 0x00, 0x0f }; data.data = new TLV[] { tlv }; flap.data = data; return flap; // service.getRunnableService().sendToSocket(flap); } private Flap requestContactListUpdate(Date lastUpdate, int itemNumber) { service.log("--- request contact list update"); Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_SERVERSIDEINFO; data.subtypeId = ICQConstants.SNAC_SERVERSIDEINFO_CLUPD; data.requestId = ICQConstants.SNAC_SERVERSIDEINFO_CLUPD; byte[] cldata = new byte[6]; int updateSeconds = (int) (lastUpdate.getTime() / 1000); byte[] buffer = new byte[4]; buffer = ProtocolUtils.int2ByteBE(updateSeconds); System.arraycopy(buffer, 0, cldata, 0, 4); buffer = ProtocolUtils.short2ByteBE((short) itemNumber); System.arraycopy(buffer, 0, cldata, 4, 2); data.plainData = cldata; flap.data = data; return flap; } private Flap requestContactList() throws ICQException { service.log("--- request contact list"); Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_SERVERSIDEINFO; data.subtypeId = ICQConstants.SNAC_SERVERSIDEINFO_CLREQ; data.requestId = ICQConstants.SNAC_SERVERSIDEINFO_CLREQ; flap.data = data; return flap; // service.getRunnableService().sendToSocket(flap); } private Flap requestLocationServiceLimits() throws ICQException { service.log("--- request location service limits"); Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_LOCATION; data.subtypeId = ICQConstants.SNAC_LOCATION_PARAMREQ; data.requestId = ICQConstants.SNAC_LOCATION_PARAMREQ; flap.data = data; return flap; // service.getRunnableService().sendToSocket(flap); } private Flap requestBuddylistServiceLimits() throws ICQException { service.log("--- request buddylist service limits"); Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_BUDDYLISTMGMT; data.subtypeId = ICQConstants.SNAC_BUDDYLISTMGMT_PARAMREQ; data.requestId = ICQConstants.SNAC_BUDDYLISTMGMT_PARAMREQ; TLV tlv = new TLV(); tlv.type = (short) 0x05; tlv.value = new byte[] { 0x00, 0x03 }; data.data = new TLV[] { tlv }; flap.data = data; return flap; // service.getRunnableService().sendToSocket(flap); } private Flap requestMessagingServiceLimits() throws ICQException { service.log("--- request messaging service limits"); Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_MESSAGING; data.subtypeId = ICQConstants.SNAC_MESSAGING_PARAMREQ; data.requestId = ICQConstants.SNAC_MESSAGING_PARAMREQ; flap.data = data; return flap; // service.getRunnableService().sendToSocket(flap); } private Flap requestPrivacyServiceLimits() throws ICQException { service.log("--- request privacy service limits"); Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_PRIVACYMGMT; data.subtypeId = ICQConstants.SNAC_PRIVACYMGMT_PARAMREQ; data.requestId = ICQConstants.SNAC_PRIVACYMGMT_PARAMREQ; flap.data = data; return flap; // service.getRunnableService().sendToSocket(flap); } private Flap sendClientFamiliesVersions() throws ICQException { service.log("--- send client family versions"); Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_GENERIC; data.subtypeId = ICQConstants.SNAC_GENERIC_SERVERSERVICESVERSIONREQ; data.requestId = ICQConstants.SNAC_GENERIC_SERVERSERVICESVERSIONREQ; data.plainData = ICQConstants.LOCAL_FAMILIES_VERSIONS; flap.data = data; return flap; // service.getRunnableService().sendToSocket(flap); } private Flap requestRateLimits() throws ICQException { service.log("--- request rate limits"); Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_GENERIC; data.subtypeId = ICQConstants.SNAC_GENERIC_RATELIMITINFOREQ; data.requestId = ICQConstants.SNAC_GENERIC_RATELIMITINFOREQ; flap.data = data; return flap; // service.getRunnableService().sendToSocket(flap); } private void parseRateLimits(Snac snac) throws ICQException { int rateClassCount = ProtocolUtils.unsignedShort2Int(ProtocolUtils.bytes2ShortBE(snac.plainData)); RateLimit[] limits = new RateLimit[rateClassCount]; int pos = 2; for (int i = 0; i < rateClassCount; i++) { byte[] buffer = new byte[4]; System.arraycopy(snac.plainData, pos, buffer, 0, 2); short classId = ProtocolUtils.bytes2ShortBE(buffer); pos += 2; System.arraycopy(snac.plainData, pos, buffer, 0, 4); int windowSize = ProtocolUtils.bytes2IntBE(buffer); pos += 4; System.arraycopy(snac.plainData, pos, buffer, 0, 4); int clearLevel = ProtocolUtils.bytes2IntBE(buffer); pos += 4; System.arraycopy(snac.plainData, pos, buffer, 0, 4); int alertLevel = ProtocolUtils.bytes2IntBE(buffer); pos += 4; System.arraycopy(snac.plainData, pos, buffer, 0, 4); int limitLevel = ProtocolUtils.bytes2IntBE(buffer); pos += 4; System.arraycopy(snac.plainData, pos, buffer, 0, 4); int disconnectLevel = ProtocolUtils.bytes2IntBE(buffer); pos += 4; System.arraycopy(snac.plainData, pos, buffer, 0, 4); int currentLevel = ProtocolUtils.bytes2IntBE(buffer); pos += 4; System.arraycopy(snac.plainData, pos, buffer, 0, 4); int maxLevel = ProtocolUtils.bytes2IntBE(buffer); pos += 4; System.arraycopy(snac.plainData, pos, buffer, 0, 4); int lastTime = ProtocolUtils.bytes2IntBE(buffer); pos += 4; byte currentState = snac.plainData[pos]; pos++; RateLimit limit = new RateLimit(classId, windowSize, clearLevel, alertLevel, limitLevel, disconnectLevel, currentLevel, maxLevel, lastTime, currentState); limits[i] = limit; } // List<RateGroup> groups = new LinkedList<RateGroup>(); // while(pos<snac.plainData.length){ for (int i = 0; i < rateClassCount; i++) { byte[] buffer = new byte[4]; System.arraycopy(snac.plainData, pos, buffer, 0, 2); short groupId = ProtocolUtils.bytes2ShortBE(buffer); pos += 2; System.arraycopy(snac.plainData, pos, buffer, 0, 2); int familyCount = ProtocolUtils.unsignedShort2Int(ProtocolUtils.bytes2ShortBE(buffer)); pos += 2; int[] families = new int[familyCount]; for (int j = 0; j < familyCount; j++) { System.arraycopy(snac.plainData, pos, buffer, 0, 4); families[j] = ProtocolUtils.bytes2IntBE(buffer); pos += 4; } RateGroup rateGroup = new RateGroup(groupId, families); limits[i].rateGroup = rateGroup; // groups.add(rateGroup); } service.setRateLimits(limits); } private Flap sendRateLimitsAck() throws ICQException { service.log("--- send rate limits ack"); Flap flap = new Flap(); flap.channel = ICQConstants.FLAP_CHANNELL_DATA; Snac data = new Snac(); data.serviceId = ICQConstants.SNAC_FAMILY_GENERIC; data.subtypeId = ICQConstants.SNAC_GENERIC_RATELIMITGROUPADD; data.requestId = ICQConstants.SNAC_GENERIC_RATELIMITGROUPADD; byte[] rateIds = new byte[service.getRateLimits().length * 2]; for (int i = 0; i < service.getRateLimits().length; i++) { byte[] id = ProtocolUtils.short2ByteBE(service.getRateLimits()[i].rateGroup.id); System.arraycopy(id, 0, rateIds, i * 2, 2); } data.plainData = rateIds; flap.data = data; return flap; } public void deactivateTimer() { service.log("deactivate auth timer"); expireTimerTask.disconnect = false; if (startupTimer != null && task != null) { task.cancel(false); } else { service.log("deactivate auth timer failed"); } } class AuthExpireTimerTask implements Runnable { public volatile boolean disconnect = true; @Override public void run() { if (disconnect && (service.getProcessor() == null || service.getProcessor() instanceof AuthenticationProcessor)) { service.log("auth timeout"); authCookie = null; service.getRunnableService().disconnect(); } } } @Override public void onDisconnect() { deactivateTimer(); } }